﻿// LogViewControl.cpp
#include "logger\LogViewControl.h"

#if defined(_WIN32)

// All heavy includes are now ONLY in the .cpp file
#include <CommCtrl.h>
#include <Richedit.h>
#include <tchar.h>
#include <uxtheme.h>
#include <vssym32.h>

#include <map>
#include <queue>

#include "LogViewController.h"
#include "logger\LogBroker.h"
#include "logger\LogMessageInfo.h"
#include "logger\WindowSink.h"

#pragma comment(lib, "uxtheme.lib")

namespace Logging {
// --- Control IDs can remain as an internal detail ---
enum class ControlId : int {
  RichEdit = 2000,
  GroupFilter,
  CheckTrace,
  CheckDebug,
  CheckInfo,
  CheckWarn,
  CheckError,
  CheckCritical,
  StaticSearch,
  EditSearch,
  CheckRegex,
  ButtonClear,
  StatusBar,
  CheckAutoScroll,
};

struct ThemeColors {
  // RichEdit Colors
  COLORREF richEditBg;
  COLORREF richEditTextDefault;
  std::map<LogLevel, COLORREF> logLevelColors;

  // Other Controls (CheckBox, Button, etc.)
  COLORREF controlBg;
  COLORREF controlText;
  HBRUSH hControlBgBrush;  // 用于 WM_CTLCOLORSTATIC 的背景画刷
};

// --- Public constants definition ---
const wchar_t* WC_LOGVIEW = L"SuperLogger.LogViewControl";

// ========================================================================
// The Hidden Implementation Class Definition
// ========================================================================
class CLogViewControl::Impl {
 public:
  Impl();
  ~Impl();

  void SetLogCategory(const std::string& category);

  // Message handlers (these were the private methods of the old class)
  LRESULT OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct);
  LRESULT OnDestroy();
  LRESULT OnSize(int width, int height);
  LRESULT OnCommand(int wmId, int wmEvent);
  LRESULT OnLogReady();
  LRESULT OnClear();
  LRESULT OnCtlColor(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

  void SetTheme(Theme theme);
  void ApplyCurrentTheme();
  COLORREF GetColorForLogLevel(LogLevel level);
  static void InitializeThemes();

  void AppendTextToRichEdit(const LogMessageInfo& info);

 private:
  friend class CLogViewControl;
  void RefreshDisplay();
  FilterState GatherFilterStateFromUI() const;
  void PopulateRichEdit(const std::vector<LogMessageInfo>& logs);

  // Helper functions
  void CreateChildControls(HINSTANCE hInstance);
  void SetChildControlsFont();
  void LayoutChildControls(int width, int height);
  void LayoutChildControls1(int width, int height);
  void LayoutChildControls2(int width, int height);

  void UpdateStatusBarLayout(int width, int height, int topOffset);
  void UpdateStatusBarText();
  void OnAutoScrollClicked();

  // All the state is now stored here, hidden from the public header.
  HWND m_hWnd = nullptr;  // Handle to the parent CLogViewControl window
  LogViewController m_controller;
  HFONT m_hFontUI = nullptr;
  HWND m_hRichEdit = nullptr;  // **Store the RichEdit handle here!**
  std::vector<HWND> m_logLevelCheckBoxes;

  HWND m_hStatusBarWnd = nullptr;     // 状态栏的容器窗口
  HWND m_hStatusTotal = nullptr;      // "总计" 静态文本
  HWND m_hStatusDisplayed = nullptr;  // "已显示" 静态文本
  HWND m_hStatusError = nullptr;      // "错误" 静态文本
  HWND m_hStatusWarn = nullptr;       // "警告" 静态文本
  HWND m_hChkAutoScroll = nullptr;    // "Auto-Scroll" 复选框

  size_t m_nTotalLogs = 0;
  size_t m_nDisplayedLogs = 0;
  std::map<LogLevel, size_t> m_logLevelCounts;  // 存储每个级别的日志数量

  bool m_bAutoScroll = true;

  std::shared_ptr<WindowSink> m_sink;  // 用于接收日志的 Sink 对象
  std::string m_category;              // 当前订阅的日志类别

  Theme m_currentTheme = Theme::Light;           // 默认亮色主题
  static std::map<Theme, ThemeColors> s_themes;  // 静态存储所有主题
  static bool s_themesInitialized;               // 确保只初始化一次
};

const wchar_t* GetLogViewClass() { return WC_LOGVIEW; }

// --- 控件类注册 ---
void RegisterLogViewControl(HINSTANCE hInstance) {
  WNDCLASS wc = {};
  wc.lpfnWndProc = CLogViewControl::s_WindowProc;
  wc.hInstance = hInstance;
  wc.lpszClassName = WC_LOGVIEW;
  wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  wc.style = CS_HREDRAW | CS_VREDRAW;
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  RegisterClass(&wc);
}

std::map<CLogViewControl::Theme, ThemeColors> CLogViewControl::Impl::s_themes;
bool CLogViewControl::Impl::s_themesInitialized = false;

// ========================================================================
// Public CLogViewControl methods (forwarding calls to the Impl)
// ========================================================================

CLogViewControl::CLogViewControl() : m_pImpl(std::make_unique<Impl>()) {
  // The hWnd parameter is not used here, as the actual handle will be
  // set during the WM_CREATE process. The pointer is passed via lParam.
}

// **CRUCIAL**: The definition of the destructor.
// This empty definition allows the compiler to correctly destroy m_pImpl.
CLogViewControl::~CLogViewControl() = default;

// Move operations
CLogViewControl::CLogViewControl(CLogViewControl&&) noexcept = default;
CLogViewControl& CLogViewControl::operator=(CLogViewControl&&) noexcept =
    default;

void CLogViewControl::SetLogCategory(const std::string& category) {
  if (m_pImpl) {
    m_pImpl->SetLogCategory(category);
  }
}

void CLogViewControl::SetPattern(const std::string& pattern) {
  if (m_pImpl) {
    m_pImpl->m_controller.SetPattern(pattern);
  }
}

HWND CLogViewControl::GetHwnd() const {
  // 检查 m_pImpl 是否有效，并返回其内部的 HWND
  if (m_pImpl) {
    return m_pImpl->m_hWnd;
  }
  return nullptr;
}

void CLogViewControl::SetTheme(Theme theme) {
  if (m_pImpl) {
    m_pImpl->SetTheme(theme);
  }
}

// ========================================================================
// Static Window Procedure (The Bridge)
// ========================================================================
LRESULT CALLBACK CLogViewControl::s_WindowProc(HWND hWnd, UINT uMsg,
                                               WPARAM wParam, LPARAM lParam) {
  CLogViewControl* pThis = nullptr;
  if (uMsg == WM_NCCREATE) {
    CREATESTRUCT* pCreate = reinterpret_cast<CREATESTRUCT*>(lParam);
    pThis = reinterpret_cast<CLogViewControl*>(pCreate->lpCreateParams);
    SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pThis));
  } else {
    pThis = reinterpret_cast<CLogViewControl*>(
        GetWindowLongPtr(hWnd, GWLP_USERDATA));
  }

  // If we have a valid 'this' pointer, forward the message to its
  // implementation
  if (pThis && pThis->m_pImpl) {
    switch (uMsg) {
      case WM_CREATE:
        return pThis->m_pImpl->OnCreate(
            hWnd, reinterpret_cast<LPCREATESTRUCT>(lParam));
      case WM_SIZE:
        return pThis->m_pImpl->OnSize(LOWORD(lParam), HIWORD(lParam));
      case WM_COMMAND:
        return pThis->m_pImpl->OnCommand(LOWORD(wParam), HIWORD(wParam));
      case WM_DESTROY:
        return pThis->m_pImpl->OnDestroy();
      case WM_NCDESTROY: {
        SetWindowLongPtr(hWnd, GWLP_USERDATA, 0);
        delete pThis;
        return 0;
      }
      case WM_SINK_LOG_READY:
        return pThis->m_pImpl->OnLogReady();
      case WM_CTLCOLORSTATIC:
      //{
      //  const auto& colors =
      //  pThis->m_pImpl->s_themes.at(pThis->m_pImpl->m_currentTheme); HDC
      //  hdcStatic = (HDC)wParam; SetTextColor(hdcStatic, colors.controlText);
      //  SetBkColor(hdcStatic, colors.controlBg);
      //  return (LRESULT)colors.hControlBgBrush;
      //}
      case WM_CTLCOLORBTN:
        return pThis->m_pImpl->OnCtlColor(hWnd, uMsg, wParam, lParam);
    }
  }
  return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

// ========================================================================
// Implementation of CLogViewControl::Impl methods
// ========================================================================
CLogViewControl::Impl::Impl() { InitializeThemes(); }

CLogViewControl::Impl::~Impl() {
  if (s_themesInitialized) {
    for (auto& pair : s_themes) {
      DeleteObject(pair.second.hControlBgBrush);
    }
    s_themes.clear();
    s_themesInitialized = false;
  }
}

void CLogViewControl::Impl::SetLogCategory(const std::string& category) {
  if (m_category == category) {
    return;  // 类别未改变，无需操作
  }

  auto& broker = LogBroker::GetInstance();

  // 1. 如果已经有一个 Sink，先从旧的类别注销
  if (m_sink) {
    broker.UnregisterSink(m_sink, m_category);
  }

  // 2. 更新类别
  m_category = category;

  // 3. 用新的类别重新注册 Sink
  if (m_sink) {
    broker.RegisterSink(m_sink, m_category);
  }

  // 4. 清空当前视图并刷新，以显示新类别的内容
  m_controller.Clear();
  RefreshDisplay();
}

LRESULT CLogViewControl::Impl::OnCreate(HWND hWnd,
                                        LPCREATESTRUCT lpCreateStruct) {
  m_hWnd = hWnd;  // Store our own window handle
  CreateChildControls(lpCreateStruct->hInstance);

  // **在这里获取并保存RichEdit的句柄**
  m_hRichEdit = GetDlgItem(m_hWnd, static_cast<int>(ControlId::RichEdit));
  if (!m_hRichEdit) {
    // Critical error, we can't function without the main control
    MessageBoxW(hWnd, L"Failed to find RichEdit control after creation!",
                L"Fatal Error", MB_OK | MB_ICONERROR);
    return -1;  // Abort window creation
  }

  HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(m_hWnd, GWLP_HINSTANCE);
  m_hStatusBarWnd =
      CreateWindowEx(0, _T("STATIC"), NULL, WS_CHILD | WS_VISIBLE, 0, 0, 10,
                     10,  // 初始位置和大小，将在 OnSize 中调整
                     m_hWnd, (HMENU)ControlId::StatusBar,  // 使用一个唯一的ID
                     hInstance, NULL);

  // (注意：它们的父窗口是 m_hStatusBarWnd)
  m_hStatusTotal = CreateWindowEx(0, _T("STATIC"), _T("总计: 0"),
                                  WS_CHILD | WS_VISIBLE | SS_LEFT, 0, 0, 10, 10,
                                  m_hStatusBarWnd, NULL, hInstance, NULL);
  m_hStatusDisplayed = CreateWindowEx(
      0, _T("STATIC"), _T("已显示: 0"), WS_CHILD | WS_VISIBLE | SS_LEFT, 0, 0,
      10, 10, m_hStatusBarWnd, NULL, hInstance, NULL);
  m_hStatusError = CreateWindowEx(0, _T("STATIC"), _T("错误: 0"),
                                  WS_CHILD | WS_VISIBLE | SS_LEFT, 0, 0, 10, 10,
                                  m_hStatusBarWnd, NULL, hInstance, NULL);
  m_hStatusWarn = CreateWindowEx(0, _T("STATIC"), _T("警告: 0"),
                                 WS_CHILD | WS_VISIBLE | SS_LEFT, 0, 0, 10, 10,
                                 m_hStatusBarWnd, NULL, hInstance, NULL);

  m_hChkAutoScroll = CreateWindowEx(
      0, _T("BUTTON"), _T("Auto-Scroll"),
      WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, 0, 0, 10, 10, m_hWnd,
      (HMENU)ControlId::CheckAutoScroll, hInstance, NULL);

  SendMessage(m_hChkAutoScroll, BM_SETCHECK,
              m_bAutoScroll ? BST_CHECKED : BST_UNCHECKED, 0);

  SetChildControlsFont();

  // ======================[ 核心改动 4: 创建并注册 Sink ]======================
  // 1. 创建一个 WindowSink，目标窗口是自己
  m_sink =
      std::make_shared<WindowSink>(static_cast<NativeWindowHandle>(m_hWnd));

  // 2. 设置默认监听类别为通配符 "*"
  m_category = "*";

  // 3. 将此 Sink 注册到 LogBroker
  LogBroker::GetInstance().RegisterSink(m_sink, m_category);

  // 4. 移除旧的 SetNotificationCallback 调用
  // Logging::LogBroker::GetInstance().SetNotificationCallback(...) <-- 已删除

  RECT rcClient;
  GetClientRect(m_hWnd, &rcClient);
  LayoutChildControls(rcClient.right - rcClient.left,
                      rcClient.bottom - rcClient.top);

  RefreshDisplay();  // Perform an initial refresh
  return 0;
}

LRESULT CLogViewControl::Impl::OnDestroy() {
  if (m_hFontUI) {
    DeleteObject(m_hFontUI);
    m_hFontUI = nullptr;
  }

  // ======================[ 核心改动 5: 注销 Sink ]======================
  // 确保在窗口销毁时，从 LogBroker 中移除我们的 Sink，防止野指针调用
  if (m_sink) {
    LogBroker::GetInstance().UnregisterSink(m_sink, m_category);
    m_sink.reset();
  }
  // Logging::LogBroker::GetInstance().SetNotificationCallback(nullptr); <--
  // 已删除

  return 0;
}

LRESULT CLogViewControl::Impl::OnCommand(int wmId, int wmEvent) {
  ControlId id = static_cast<ControlId>(wmId);
  bool needs_refresh = false;

  switch (id) {
    case ControlId::ButtonClear:
      if (wmEvent == BN_CLICKED) {
        m_controller.Clear();
        m_nTotalLogs = 0;
        m_nDisplayedLogs = 0;
        m_logLevelCounts.clear();
        needs_refresh = true;
      }
      break;
    case ControlId::CheckTrace:
    case ControlId::CheckDebug:
    case ControlId::CheckInfo:
    case ControlId::CheckWarn:
    case ControlId::CheckError:
    case ControlId::CheckCritical:
    case ControlId::CheckRegex:
      if (wmEvent == BN_CLICKED) needs_refresh = true;
      break;
    case ControlId::EditSearch:
      if (wmEvent == EN_CHANGE) needs_refresh = true;
      break;
    case ControlId::CheckAutoScroll:
      if (wmEvent == BN_CLICKED) {
        OnAutoScrollClicked();  // 不需要刷新，只处理滚动状态
      }
      break;
  }

  if (wmEvent == BN_CLICKED || wmEvent == EN_CHANGE) {
    if (id >= ControlId::CheckTrace && id <= ControlId::CheckRegex) {
      needs_refresh = true;
    }
  }

  if (needs_refresh) {
    RefreshDisplay();
  }

  return 0;
}

LRESULT CLogViewControl::Impl::OnLogReady() {
  std::queue<LogMessageInfo> logs_to_process;

  // =============[ 核心改动 6: 从自己的 Sink 拉取日志 ]=============
  // 不再从全局的 LogBroker 拉取，而是从与此窗口绑定的 Sink 拉取
  if (m_sink) {
    m_sink->DrainTo(logs_to_process);
  }

  if (logs_to_process.empty()) {
    return 0;
  }

  while (!logs_to_process.empty()) {
    const auto& log = logs_to_process.front();
    m_nTotalLogs++;
    m_logLevelCounts[log.level]++;
    m_controller.AddLog(std::move(logs_to_process.front()));
    logs_to_process.pop();
  }

  RefreshDisplay();

  return 0;
}

LRESULT CLogViewControl::Impl::OnClear() {
  m_controller.Clear();
  return 0;
}

LRESULT CLogViewControl::Impl::OnSize(int width, int height) {
  LayoutChildControls(width, height);
  return 0;
}

/**
 * @brief 处理子控件的颜色设置消息，以健壮的方式实现透明背景。
 *
 * 这是最终的推荐方案，它同时兼容启用了视觉样式和未启用视觉样式的场景。
 *
 * @param hWnd 父窗口句柄 (即 LogViewControl 的句柄)
 * @param uMsg 消息类型 (WM_CTLCOLORSTATIC 或 WM_CTLCOLORBTN)
 * @param wParam 子控件的设备上下文 (DC) 句柄
 * @param lParam 子控件的窗口句柄
 * @return HBRUSH 用于绘制背景的画刷句柄
 */
LRESULT CLogViewControl::Impl::OnCtlColor(HWND /*hWnd*/, UINT uMsg,
                                          WPARAM wParam, LPARAM lParam) {
  HWND hwndChild = (HWND)lParam;
  int childId = GetDlgCtrlID(hwndChild);

  const auto& colors = s_themes.at(m_currentTheme);
  HDC hdc = (HDC)wParam;

  // 如果是状态栏背景板，或者状态栏上的静态文本，直接填充背景色
  if (childId == static_cast<int>(ControlId::StatusBar) ||
      hwndChild == m_hStatusTotal || hwndChild == m_hStatusDisplayed ||
      hwndChild == m_hStatusError || hwndChild == m_hStatusWarn ||
      hwndChild == m_hChkAutoScroll) {
    SetTextColor(hdc, colors.controlText);
    SetBkColor(hdc, colors.controlBg);
    return (LRESULT)colors.hControlBgBrush;
  }

  // 如果是复选框或其他需要透明背景的控件
  if (uMsg == WM_CTLCOLORBTN || uMsg == WM_CTLCOLORSTATIC) {
    // 尝试使用主题API绘制父窗口背景，实现透明效果
    HRESULT hr = DrawThemeParentBackground(hwndChild, hdc, NULL);
    if (SUCCEEDED(hr)) {
      // 背景已由主题引擎绘制，我们只需返回一个空画刷
      return (LRESULT)GetStockObject(NULL_BRUSH);
    }

    // 回退到经典方法
    SetTextColor(hdc, colors.controlText);
    SetBkMode(hdc, TRANSPARENT);
    // 这里返回父窗口的背景色画刷
    return (LRESULT)GetSysColorBrush(COLOR_WINDOW);  // 假设父窗口背景是这个
  }

  return DefWindowProc(m_hWnd, uMsg, wParam, lParam);
}

// SRP: Gathers all filter settings from UI controls into a data structure.
FilterState CLogViewControl::Impl::GatherFilterStateFromUI() const {
  FilterState filters;

  if (IsDlgButtonChecked(m_hWnd, static_cast<int>(ControlId::CheckTrace)))
    filters.enabled_levels.insert(LogLevel::kTrace);
  if (IsDlgButtonChecked(m_hWnd, static_cast<int>(ControlId::CheckDebug)))
    filters.enabled_levels.insert(LogLevel::kDebug);
  if (IsDlgButtonChecked(m_hWnd, static_cast<int>(ControlId::CheckInfo)))
    filters.enabled_levels.insert(LogLevel::kInfo);
  if (IsDlgButtonChecked(m_hWnd, static_cast<int>(ControlId::CheckWarn)))
    filters.enabled_levels.insert(LogLevel::kWarn);
  if (IsDlgButtonChecked(m_hWnd, static_cast<int>(ControlId::CheckError)))
    filters.enabled_levels.insert(LogLevel::kError);
  if (IsDlgButtonChecked(m_hWnd, static_cast<int>(ControlId::CheckCritical)))
    filters.enabled_levels.insert(LogLevel::kCritical);

  char search_buffer[256] = {0};
  GetWindowTextA(GetDlgItem(m_hWnd, static_cast<int>(ControlId::EditSearch)),
                 search_buffer, 256);
  filters.search_term = search_buffer;

  filters.use_regex =
      (IsDlgButtonChecked(m_hWnd, static_cast<int>(ControlId::CheckRegex)) ==
       BST_CHECKED);

  return filters;
}

// SRP: Populates the RichEdit control from a vector of logs.
void CLogViewControl::Impl::PopulateRichEdit(
    const std::vector<LogMessageInfo>& logs) {
  SendMessage(m_hRichEdit, WM_SETREDRAW, FALSE, 0);
  SetWindowTextW(m_hRichEdit, L"");

  m_nDisplayedLogs = logs.size();

  for (const auto& log : logs) {
    AppendTextToRichEdit(log);
  }

  SendMessage(m_hRichEdit, WM_SETREDRAW, TRUE, 0);
  RedrawWindow(m_hRichEdit, NULL, NULL,
               RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);

  if (m_bAutoScroll) {
    SendMessage(m_hRichEdit, WM_VSCROLL, SB_BOTTOM, 0);
  }
}

// Main refresh logic
void CLogViewControl::Impl::RefreshDisplay() {
  // 1. Get filter state from UI
  FilterState filters = GatherFilterStateFromUI();
  // 2. Ask controller for filtered data
  std::vector<LogMessageInfo> logs_to_display =
      m_controller.GetFilteredLogs(filters);
  // 3. Render the data
  PopulateRichEdit(logs_to_display);
  // 4. Update status bar with the latest counts
  UpdateStatusBarText();
}

// --- 辅助函数实现 ---

void CLogViewControl::Impl::CreateChildControls(HINSTANCE hInstance) {
  // 使用 lambda 简化创建过程
  auto Create = [&](const wchar_t* className, const wchar_t* text, DWORD style,
                    ControlId id, int x, int y, int w, int h) {
    auto hWnd = CreateWindowW(className, text, WS_CHILD | WS_VISIBLE | style, x,
                              y, w, h, m_hWnd, (HMENU)id, hInstance, NULL);
    if (style & BS_AUTOCHECKBOX) m_logLevelCheckBoxes.push_back(hWnd);
    return hWnd;
  };

  // RichEdit
  Create(MSFTEDIT_CLASS, L"",
         WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | ES_READONLY,
         ControlId::RichEdit, 0, 0, 0, 0);

  // Create(L"BUTTON", L"Filter by Level", BS_GROUPBOX, ControlId::GroupFilter,
  // 0,
  //        0, 0, 0);
  Create(L"BUTTON", L"Trace", BS_AUTOCHECKBOX, ControlId::CheckTrace, 0, 0, 0,
         0);
  Create(L"BUTTON", L"Debug", BS_AUTOCHECKBOX, ControlId::CheckDebug, 0, 0, 0,
         0);
  Create(L"BUTTON", L"Info", BS_AUTOCHECKBOX, ControlId::CheckInfo, 0, 0, 0, 0);
  Create(L"BUTTON", L"Warn", BS_AUTOCHECKBOX, ControlId::CheckWarn, 0, 0, 0, 0);
  Create(L"BUTTON", L"Error", BS_AUTOCHECKBOX, ControlId::CheckError, 0, 0, 0,
         0);
  Create(L"BUTTON", L"Critical", BS_AUTOCHECKBOX, ControlId::CheckCritical, 0,
         0, 0, 0);

  Create(L"STATIC", L"Search:", SS_CENTER | SS_CENTERIMAGE,
         ControlId::StaticSearch, 0, 0, 0, 0);
  Create(L"EDIT", L"", WS_BORDER | ES_AUTOHSCROLL, ControlId::EditSearch, 0, 0,
         0, 0);
  Create(L"BUTTON", L"Use Regex", BS_AUTOCHECKBOX, ControlId::CheckRegex, 0, 0,
         0, 0);

  Create(L"BUTTON", L"Clear", BS_PUSHBUTTON, ControlId::ButtonClear, 0, 0, 0,
         0);

  // Set default checks
  CheckDlgButton(m_hWnd, static_cast<int>(ControlId::CheckTrace), BST_CHECKED);
  CheckDlgButton(m_hWnd, static_cast<int>(ControlId::CheckDebug), BST_CHECKED);
  CheckDlgButton(m_hWnd, static_cast<int>(ControlId::CheckInfo), BST_CHECKED);
  CheckDlgButton(m_hWnd, static_cast<int>(ControlId::CheckWarn), BST_CHECKED);
  CheckDlgButton(m_hWnd, static_cast<int>(ControlId::CheckError), BST_CHECKED);
  CheckDlgButton(m_hWnd, static_cast<int>(ControlId::CheckCritical),
                 BST_CHECKED);
}

void CLogViewControl::Impl::SetChildControlsFont() {
  NONCLIENTMETRICSW ncm = {sizeof(ncm)};
  if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0)) {
    m_hFontUI = CreateFontIndirectW(&ncm.lfMessageFont);
  }
  if (m_hFontUI) {
    EnumChildWindows(
        m_hWnd,
        [](HWND hChild, LPARAM lParam) -> BOOL {
          SendMessage(hChild, WM_SETFONT, (WPARAM)lParam, TRUE);
          return TRUE;
        },
        (LPARAM)m_hFontUI);
    EnumChildWindows(
        m_hStatusBarWnd,
        [](HWND hChild, LPARAM lParam) -> BOOL {
          SendMessage(hChild, WM_SETFONT, (WPARAM)lParam, TRUE);
          return TRUE;
        },
        (LPARAM)m_hFontUI);
  }
}

void CLogViewControl::Impl::LayoutChildControls(int width, int height) {
  // TODO: smart DPI
  // const float dpiScale = GetDpiForWindow(m_hWnd) / 96.0f;
  // const int PADDING = static_cast<int>(8 * dpiScale);

  if (width <= 0 || height <= 0) return;

  // --- 1. 定义布局常量 ---
  const int PADDING = 8;
  const int CONTROL_HEIGHT = 25;
  const int ROW_SPACING = 6;
  const int TOOLBAR_HEIGHT = (CONTROL_HEIGHT * 2) + (PADDING * 2) + ROW_SPACING;
  const int STATUS_BAR_HEIGHT = 24;  // 新增状态栏高度常量

  // --- 2. 布局顶部工具栏 (您的代码保持不变) ---
  // ... (布局第一行和第二行的代码)
  const int Y_ROW1 = PADDING;
  int current_x_r1 = PADDING;
  const int CHK_LEVEL_WIDTH = 60;
  auto LayoutCheckbox = [&](ControlId id) {
    MoveWindow(GetDlgItem(m_hWnd, static_cast<int>(id)), current_x_r1, Y_ROW1,
               CHK_LEVEL_WIDTH, CONTROL_HEIGHT, TRUE);
    current_x_r1 += CHK_LEVEL_WIDTH;
  };
  LayoutCheckbox(ControlId::CheckTrace);
  LayoutCheckbox(ControlId::CheckDebug);
  LayoutCheckbox(ControlId::CheckInfo);
  LayoutCheckbox(ControlId::CheckWarn);
  LayoutCheckbox(ControlId::CheckError);
  LayoutCheckbox(ControlId::CheckCritical);

  const int BTN_CLEAR_WIDTH = 90;
  int clear_btn_x = width - PADDING - BTN_CLEAR_WIDTH;
  MoveWindow(GetDlgItem(m_hWnd, static_cast<int>(ControlId::ButtonClear)),
             clear_btn_x, Y_ROW1, BTN_CLEAR_WIDTH, CONTROL_HEIGHT, TRUE);

  const int Y_ROW2 = Y_ROW1 + CONTROL_HEIGHT + ROW_SPACING;
  int current_x_r2 = PADDING;

  const int CHK_REGEX_WIDTH = 90;
  int regex_x = width - PADDING - CHK_REGEX_WIDTH;
  MoveWindow(GetDlgItem(m_hWnd, static_cast<int>(ControlId::CheckRegex)),
             regex_x, Y_ROW2, CHK_REGEX_WIDTH, CONTROL_HEIGHT, TRUE);

  const int LBL_SEARCH_WIDTH = 50;
  MoveWindow(GetDlgItem(m_hWnd, static_cast<int>(ControlId::StaticSearch)),
             current_x_r2, Y_ROW2, LBL_SEARCH_WIDTH, CONTROL_HEIGHT, TRUE);
  current_x_r2 += LBL_SEARCH_WIDTH;

  int search_edit_x = current_x_r2;
  int search_edit_width = regex_x - search_edit_x - PADDING;
  const int MIN_SEARCH_WIDTH = 100;
  if (search_edit_width < MIN_SEARCH_WIDTH) {
    search_edit_width = MIN_SEARCH_WIDTH;
  }
  MoveWindow(GetDlgItem(m_hWnd, static_cast<int>(ControlId::EditSearch)),
             search_edit_x, Y_ROW2, search_edit_width, CONTROL_HEIGHT, TRUE);

  // --- 3. 布局状态栏 (在 RichEdit 之前，以便计算其高度) ---
  int statusBarTop = height - STATUS_BAR_HEIGHT;
  MoveWindow(m_hStatusBarWnd, 0, height - STATUS_BAR_HEIGHT, width,
             STATUS_BAR_HEIGHT, TRUE);
  UpdateStatusBarLayout(width, STATUS_BAR_HEIGHT, statusBarTop);

  // --- 4. 布局富文本日志显示区 (填充剩余空间) ---
  int richEditY = TOOLBAR_HEIGHT;
  // 高度 = 总高度 - 工具栏高度 - 状态栏高度
  int richEditHeight = height - TOOLBAR_HEIGHT - STATUS_BAR_HEIGHT;

  // 安全检查，防止窗口过小时宽度/高度为负
  if (richEditHeight < 0) richEditHeight = 0;

  MoveWindow(m_hRichEdit, PADDING, richEditY,
             width - (PADDING * 2),  // 宽度
             richEditHeight,         // 修正后的高度
             TRUE);
}

// Log view align right
void CLogViewControl::Impl::LayoutChildControls1(int width, int height) {
  const int PADDING = 10;
  const int LEFT_PANEL_WIDTH = 180;
  const int BUTTON_HEIGHT = 30;
  const int CHECKBOX_HEIGHT = 20;

  // --- Layout Left Panel ---
  int current_y = PADDING;

  MoveWindow(GetDlgItem(m_hWnd, static_cast<int>(ControlId::ButtonClear)),
             PADDING, current_y, LEFT_PANEL_WIDTH, BUTTON_HEIGHT, TRUE);
  current_y += BUTTON_HEIGHT + PADDING * 2;

  const int FILTER_GROUP_HEIGHT = 185;
  MoveWindow(GetDlgItem(m_hWnd, static_cast<int>(ControlId::GroupFilter)),
             PADDING, current_y, LEFT_PANEL_WIDTH, FILTER_GROUP_HEIGHT, TRUE);

  current_y += 20;  // GroupBox title
  const int CHECKBOX_INDENT = PADDING + 10;
  const int CHECKBOX_WIDTH = LEFT_PANEL_WIDTH - 20;

  auto LayoutCheckbox = [&](ControlId id) {
    MoveWindow(GetDlgItem(m_hWnd, static_cast<int>(id)), CHECKBOX_INDENT,
               current_y, CHECKBOX_WIDTH, CHECKBOX_HEIGHT, TRUE);
    current_y += CHECKBOX_HEIGHT + 5;
  };
  LayoutCheckbox(ControlId::CheckTrace);
  LayoutCheckbox(ControlId::CheckDebug);
  LayoutCheckbox(ControlId::CheckInfo);
  LayoutCheckbox(ControlId::CheckWarn);
  LayoutCheckbox(ControlId::CheckError);
  LayoutCheckbox(ControlId::CheckCritical);

  current_y += PADDING;  // Space after checkboxes

  MoveWindow(GetDlgItem(m_hWnd, static_cast<int>(ControlId::StaticSearch)),
             PADDING, current_y, LEFT_PANEL_WIDTH, 20, TRUE);
  current_y += 20;
  MoveWindow(GetDlgItem(m_hWnd, static_cast<int>(ControlId::EditSearch)),
             PADDING, current_y, LEFT_PANEL_WIDTH, 25, TRUE);
  current_y += 25 + 5;
  MoveWindow(GetDlgItem(m_hWnd, static_cast<int>(ControlId::CheckRegex)),
             PADDING, current_y, LEFT_PANEL_WIDTH, 20, TRUE);

  // --- Layout RichEdit ---
  int richEditX = LEFT_PANEL_WIDTH + PADDING * 2;
  int richEditY = PADDING;
  int richEditWidth =
      width > richEditX + PADDING ? width - richEditX - PADDING : 0;
  int richEditHeight = height > PADDING * 2 ? height - PADDING * 2 : 0;
  MoveWindow(GetDlgItem(m_hWnd, static_cast<int>(ControlId::RichEdit)),
             richEditX, richEditY, richEditWidth, richEditHeight, TRUE);
}

// Buttons align top one line
void CLogViewControl::Impl::LayoutChildControls2(int width, int height) {
  // --- 1. 定义布局常量 ---
  const int PADDING = 8;
  const int TOOLBAR_HEIGHT = 45;  // 顶部工具栏的总高度
  const int CONTROL_HEIGHT = 25;  // 工具栏中控件的标准高度

  // 计算控件在工具栏中垂直居中的Y坐标
  const int Y_POS = (TOOLBAR_HEIGHT - CONTROL_HEIGHT) / 2;

  // --- 2. 布局顶部工具栏 (从左到右) ---
  int current_x = PADDING;

  // 清除按钮
  const int BTN_CLEAR_WIDTH = 80;
  MoveWindow(GetDlgItem(m_hWnd, static_cast<int>(ControlId::ButtonClear)),
             current_x, Y_POS, BTN_CLEAR_WIDTH, CONTROL_HEIGHT, TRUE);
  current_x += BTN_CLEAR_WIDTH + PADDING * 2;  // 留出更大间距

  // 级别过滤复选框
  const int CHK_LEVEL_WIDTH = 70;
  auto LayoutCheckbox = [&](ControlId id) {
    MoveWindow(GetDlgItem(m_hWnd, static_cast<int>(id)), current_x, Y_POS,
               CHK_LEVEL_WIDTH, CONTROL_HEIGHT, TRUE);
    current_x += CHK_LEVEL_WIDTH;  // 复选框之间紧凑排列
  };
  LayoutCheckbox(ControlId::CheckTrace);
  LayoutCheckbox(ControlId::CheckDebug);
  LayoutCheckbox(ControlId::CheckInfo);
  LayoutCheckbox(ControlId::CheckWarn);
  LayoutCheckbox(ControlId::CheckError);
  LayoutCheckbox(ControlId::CheckCritical);

  current_x += PADDING * 2;  // 留出更大间距

  // --- 3. 布局搜索区域 (部分从右到左，实现伸缩) ---

  // 搜索标签 (固定宽度)
  const int LBL_SEARCH_WIDTH = 50;
  MoveWindow(GetDlgItem(m_hWnd, static_cast<int>(ControlId::StaticSearch)),
             current_x, Y_POS, LBL_SEARCH_WIDTH, CONTROL_HEIGHT, TRUE);
  current_x += LBL_SEARCH_WIDTH;

  // 正则表达式复选框 (从最右边开始布局)
  const int CHK_REGEX_WIDTH = 90;
  int regex_x = width - PADDING - CHK_REGEX_WIDTH;
  MoveWindow(GetDlgItem(m_hWnd, static_cast<int>(ControlId::CheckRegex)),
             regex_x, Y_POS, CHK_REGEX_WIDTH, CONTROL_HEIGHT, TRUE);

  // 搜索编辑框 (占据中间所有剩余空间)
  int search_edit_x = current_x + PADDING;
  int search_edit_width = regex_x - search_edit_x - PADDING;
  const int MIN_SEARCH_WIDTH = 100;  // 保证搜索框的最小宽度
  if (search_edit_width < MIN_SEARCH_WIDTH) {
    search_edit_width = MIN_SEARCH_WIDTH;
  }
  MoveWindow(GetDlgItem(m_hWnd, static_cast<int>(ControlId::EditSearch)),
             search_edit_x, Y_POS, search_edit_width, CONTROL_HEIGHT, TRUE);

  // --- 4. 布局富文本日志显示区 ---
  int richEditX = PADDING;
  int richEditY = TOOLBAR_HEIGHT;  // 从工具栏下方开始
  int richEditWidth = width - (PADDING * 2);
  int richEditHeight = height - TOOLBAR_HEIGHT - PADDING;

  // 安全检查，防止窗口过小时宽度/高度为负
  if (richEditWidth < 0) richEditWidth = 0;
  if (richEditHeight < 0) richEditHeight = 0;

  MoveWindow(m_hRichEdit,  // 直接使用缓存的句柄，效率更高
             richEditX, richEditY, richEditWidth, richEditHeight, TRUE);
}

void CLogViewControl::Impl::UpdateStatusBarLayout(int width, int height,
                                                  int topOffset) {
  const int kPadding = 8;
  const int kItemHeight = 20;
  // 计算控件在状态栏区域内的垂直居中位置
  const int kTopInStatus = (height - kItemHeight) / 2;
  // 计算控件相对于父窗口 m_hWnd 的最终 Y 坐标
  const int finalTop = topOffset + kTopInStatus;

  int x = kPadding;
  int widths[] = {90, 90, 70, 70};

  MoveWindow(m_hStatusTotal, x, kTopInStatus, widths[0], kItemHeight, TRUE);
  x += widths[0];
  MoveWindow(m_hStatusDisplayed, x, kTopInStatus, widths[1], kItemHeight, TRUE);
  x += widths[1];
  MoveWindow(m_hStatusError, x, kTopInStatus, widths[2], kItemHeight, TRUE);
  x += widths[2];
  MoveWindow(m_hStatusWarn, x, kTopInStatus, widths[3], kItemHeight, TRUE);

  const int kAutoScrollWidth = 80;
  MoveWindow(m_hChkAutoScroll, width - kAutoScrollWidth - kPadding, finalTop,
             kAutoScrollWidth, kItemHeight, TRUE);
}

void CLogViewControl::Impl::UpdateStatusBarText() {
  wchar_t buffer[128];

  swprintf_s(buffer, L"总计: %zu", m_nTotalLogs);
  SetWindowTextW(m_hStatusTotal, buffer);

  swprintf_s(buffer, L"已显示: %zu", m_nDisplayedLogs);
  SetWindowTextW(m_hStatusDisplayed, buffer);

  size_t errors = m_logLevelCounts.count(LogLevel::kError)
                      ? m_logLevelCounts.at(LogLevel::kError)
                      : 0;
  swprintf_s(buffer, L"错误: %zu", errors);
  SetWindowTextW(m_hStatusError, buffer);

  size_t warnings = m_logLevelCounts.count(LogLevel::kWarn)
                        ? m_logLevelCounts.at(LogLevel::kWarn)
                        : 0;
  swprintf_s(buffer, L"警告: %zu", warnings);
  SetWindowTextW(m_hStatusWarn, buffer);
}

void CLogViewControl::Impl::OnAutoScrollClicked() {
  LRESULT state = SendMessage(m_hChkAutoScroll, BM_GETCHECK, 0, 0);
  m_bAutoScroll = (state == BST_CHECKED);

  // 如果用户刚刚勾选了自动滚动，立即滚动到底部
  if (m_bAutoScroll) {
    SendMessage(m_hRichEdit, WM_VSCROLL, SB_BOTTOM, 0);
  }
}

void CLogViewControl::Impl::InitializeThemes() {
  if (s_themesInitialized) return;

  // --- Light theme ---
  ThemeColors lightTheme;
  lightTheme.richEditBg = GetSysColor(COLOR_WINDOW);
  lightTheme.richEditTextDefault = GetSysColor(COLOR_WINDOWTEXT);
  lightTheme.logLevelColors = {{LogLevel::kTrace, RGB(128, 128, 128)},
                               {LogLevel::kDebug, RGB(0, 128, 255)},
                               {LogLevel::kInfo, GetSysColor(COLOR_WINDOWTEXT)},
                               {LogLevel::kWarn, RGB(255, 165, 0)},
                               {LogLevel::kError, RGB(255, 0, 0)},
                               {LogLevel::kCritical, RGB(178, 34, 34)}};
  lightTheme.controlBg = GetSysColor(COLOR_BTNFACE);
  lightTheme.controlText = GetSysColor(COLOR_BTNTEXT);
  lightTheme.hControlBgBrush = CreateSolidBrush(lightTheme.controlBg);
  s_themes[Theme::Light] = lightTheme;

  // --- Dark theme ---
  ThemeColors darkTheme;
  darkTheme.richEditBg = RGB(30, 30, 30);
  darkTheme.richEditTextDefault = RGB(220, 220, 220);
  darkTheme.logLevelColors = {{LogLevel::kTrace, RGB(128, 128, 128)},
                              {LogLevel::kDebug, RGB(86, 156, 214)},
                              {LogLevel::kInfo, RGB(220, 220, 220)},
                              {LogLevel::kWarn, RGB(220, 200, 100)},
                              {LogLevel::kError, RGB(244, 100, 100)},
                              {LogLevel::kCritical, RGB(255, 80, 150)}};
  darkTheme.controlBg = RGB(51, 51, 51);
  darkTheme.controlText = RGB(220, 220, 220);
  darkTheme.hControlBgBrush = CreateSolidBrush(darkTheme.controlBg);
  s_themes[Theme::DarkVisualStudio] = darkTheme;

  s_themesInitialized = true;
}

// Impl内部的实现
void CLogViewControl::Impl::SetTheme(Theme theme) {
  if (m_currentTheme == theme && m_hWnd)
    return;  // 如果主题未变，则不执行任何操作

  m_currentTheme = theme;
  ApplyCurrentTheme();
}

void CLogViewControl::Impl::ApplyCurrentTheme() {
  if (!m_hWnd || s_themes.find(m_currentTheme) == s_themes.end()) {
    return;
  }

  const auto& colors = s_themes.at(m_currentTheme);

  // 1. 应用到 RichEdit
  SendMessage(m_hRichEdit, EM_SETBKGNDCOLOR, 0, (LPARAM)colors.richEditBg);

  // 1. 应用到 RichEdit
  SendMessage(m_hRichEdit, EM_SETBKGNDCOLOR, 0, (LPARAM)colors.richEditBg);

  // 2. 刷新日志内容以应用新的日志级别颜色 (RefreshDisplay 会处理)
  // RefreshDisplay(); //
  // 在这里调用会导致循环刷新，应在SetTheme的公共接口调用后手动刷新

  // 3. 强制重绘父窗口及其所有子控件以应用新颜色
  // 这将触发 WM_CTLCOLORSTATIC/BTN 等消息
  InvalidateRect(m_hWnd, NULL, TRUE);
  UpdateWindow(m_hWnd);  // 立即重绘
}

// 修改 GetColorForLogLevel 以使用主题
COLORREF CLogViewControl::Impl::GetColorForLogLevel(LogLevel level) {
  const auto& colors = s_themes.at(m_currentTheme);
  auto it = colors.logLevelColors.find(level);
  if (it != colors.logLevelColors.end()) {
    return it->second;
  }
  return colors.richEditTextDefault;  // 返回默认颜色
}

void CLogViewControl::Impl::AppendTextToRichEdit(
    const LogMessageInfo& message) {
  if (!m_hRichEdit) return;

  COLORREF color = GetColorForLogLevel(message.level);

  CHARFORMAT2W cf;
  cf.cbSize = sizeof(cf);
  cf.dwMask = CFM_COLOR;  // 移除 CFM_BOLD
  cf.dwEffects = 0;
  cf.crTextColor = color;

  if (message.level == LogLevel::kError ||
      message.level == LogLevel::kCritical) {
    cf.dwMask |= CFM_BOLD;
    cf.dwEffects |= CFE_BOLD;
  }

  int len =
      MultiByteToWideChar(CP_UTF8, 0, message.message.c_str(), -1, NULL, 0);
  std::wstring wide_msg(len, 0);
  MultiByteToWideChar(CP_UTF8, 0, message.message.c_str(), -1, &wide_msg[0],
                      len);

  // 移动到文本末尾
  SendMessageW(m_hRichEdit, EM_SETSEL, (WPARAM)-1, (LPARAM)-1);
  // 设置字符格式
  SendMessageW(m_hRichEdit, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
  // 追加文本
  SendMessageW(m_hRichEdit, EM_REPLACESEL, FALSE, (LPARAM)wide_msg.c_str());
  // 添加换行
  SendMessageW(m_hRichEdit, EM_REPLACESEL, 0, (LPARAM)L"\r");

  // ★★★ [REMOVED] 移除此处的滚动，统一由 PopulateRichEdit 控制 ★★★
  // SendMessageW(m_hRichEdit, WM_VSCROLL, SB_BOTTOM, 0);
}

// 在你的主程序中创建CLogViewControl实例时，需要 new CLogViewControl(NULL);
// 并且在主窗口的WM_DESTROY中 delete 它，以避免内存泄漏。
}  // namespace Logging

#endif  //_WIN32